knitr::opts_chunk$set(echo = TRUE, warning = FALSE, message = FALSE, cache = FALSE)

Setup for analysis

Load packages

library(tidyverse) # tidy style coding
library(brms) # Bayesian models
library(loo) # to use information criteria in brms models
library(tidybayes) # Bayesian aesthetics
library(MetBrewer) # colours
library(kableExtra) # tables
library(patchwork) # putting plots together
library(DT) # for search- and saveable tables
library(pander) # for simpler tables
library(ggdag) # to visualise casual relationships

Load in the data

\(~\)

fitness_data <- read_csv("data/SLC_fitness_data.csv") %>% 
  mutate(Fitness_vial_ID = as.factor(Fitness_vial_ID),
         Block = as.factor(Block),
         Population = as.factor(Population),
         Treatment = as.factor(Treatment),
         GFP = as.factor(GFP),
         Sex = as.factor(Sex),
         Rearing_vial = as.factor(Rearing_vial),
         Sex = as.factor(Sex),
         Total_red_offspring = Red_female_offspring + Red_male_offspring,
         Total_bw_offspring = bw_female_offspring + bw_male_offspring,
         Total_offspring = Total_red_offspring + Total_bw_offspring) %>% 
  rename(Evolution_treatment = Treatment)

# Create a function to build HTML searchable tables

my_data_table <- function(df){
  datatable(
    df, rownames=FALSE,
    autoHideNavigation = TRUE,
    extensions = c("Scroller",  "Buttons"),
    options = list(
      dom = 'Bfrtip',
      deferRender=TRUE,
      scrollX=TRUE, scrollY=400,
      scrollCollapse=TRUE,
      buttons =
        list('pageLength', 'colvis', 'csv', list(
          extend = 'pdf',
          pageSize = 'A4',
          orientation = 'landscape',
          filename = 'fitness_data')),
      pageLength = 692
    )
  )
}


my_data_table(fitness_data %>% select(-Comment))

Column explanations

Fitness_vial_ID: a unique identifier for each replicate of the fitness assays.

Block: the experiment was run in three distinct blocks, using flies from separate generations.

Population: we measured the fitness of flies from 12 independent populations that has undergone experimental evolution.

Evolution_treatment: the populations had been exposed to one of three evolutionary conditions for 20 generations: a female-limited response to selection, a male-limited response and a control condition where the evolutionary response was unconstrained.

GFP: the GFP marker carried by the population. UBI indicates the presence of a transgene that encodes ubiquitous expression of GFP, while 3xP indicates the presence of a different transgene that encodes the expression of GFP in the ocelli.

Sex: the sex of the individuals that we were measuring the fitness of.

Rearing_vial: the vial the flies developed in. This variable is included to capture variation explained by the rearing environment e.g. small differences in food moisture content or quantity. Note that females and males can have the same rearing vial.

Red_female_offspring: the number of adult female offspring sired/produced by flies sourced from one of the 12 populations.

Red_male_offspring: the number of adult male offspring sired/produced by flies sourced from one of the 12 populations.

bw_female_offspring: the number of adult female offspring sired/produced by the competitor flies in our fitness assay. bw is a recessive allele that encodes brown eye colour.

bw_male_offspring: the number of adult male offspring sired/produced by the competitor flies in our fitness assay. bw is a recessive allele that encodes brown eye colour.

Total_red_offspring: the total number (sexes pooled) of adult offspring sired/produced by flies sourced from one of the 12 populations.

Total_bw_offspring: the total number (sexes pooled) of adult offspring sired/produced by competitor flies.

Total_offspring: the total number (sexes and eye colours pooled) of adult offspring counted in each vial.

\(~\)

Modelling approach

\(~\)

Female and male fitness are fundamentally different concepts / traits. There are also several differences between our female and male fitness assays. The major difference is that the male assay contains half the number of females in any given vial than does the female assay. The logic behind this design choice is that sexually selected processes are a more important determinant of male fitness than they are female fitness, so any fitness differences may only be observed when competition for fertilisations is high.

For these reasons, we choose to split the data up and model them separately.

female_fitness <- 
  fitness_data %>%
  filter(Sex == "Female")

male_fitness <- 
  fitness_data %>%
  filter(Sex == "Male")

Fixed effects

Block: fitness might differ between the three distinct blocks we split our experiment up into. Blocks differed temporally, used flies from different generations and different batches of food. It is also possible that there were minor fluctuations in the lighting and temperature environment experienced during development between blocks. Each of these variables may introduce variation into our fitness measurements, that can be accounted for by including the Block variable in our model.

GFP: it is possible that fitness may be affected by the GFP transgene carried by each population. For example, one could imagine that any unintended fitness effects of a transgene might be of greater magnitude if it is expressed in a larger proportion of tissues, as is the case for the UBI transgene versus the 3xP transgene. Note that each GFP type is carried by an equal number of populations from each of the three evolutionary treatments.

Evolution_treatment: this is the evolution condition that populations were subject to for 20 generations. There are three levels: populations carrying female-adapted chromosomes, populations containing male-adapted chromosomes and populations carrying control chromosomes that have experienced an unlimited response to selection. This variable is central to our hypothesis.

Random effects

Rearing_vial: the vial individual flies developed within may introduce further variation into our response variable. Like Block this variable controls for micro-environmental variation.

Population: our design contained 12 independent populations of chromosomes that originated from a single outbred laboratory fly population. The populations were split and chromosomes from each were subjected to one of the three evolution treatments for 20 generations. 4 populations experienced a female-limited response to selection, 4 a male-limited response and 4 an unlimited response.

\(~\)

Female fitness

\(~\)

To estimate the fitness of females carrying each of the three chromosome types, we placed three experimental females into a yeasted vial with three female competitors that carried the bw mutation. We then introduced six males that also carried the bw mutation. We allowed them to mate and oviposit for three days, then removed all adults from the vial. 12 days later we counted all of the adult progeny in the vial and scored them for eye-colour. Progeny with red eyes were produced by the experimental females ( bw is recessive) and progeny with brown eyes were produced by the competitor females. We calculated fitness as the proportion of red eyed offspring in the vial.

\(~\)

female_fitness.01 <-
  brm(Total_red_offspring | trials(Total_offspring) ~ 1 + Evolution_treatment + GFP + Block + (1|Population) + (1|Rearing_vial),
      data = female_fitness, family = binomial(), 
      prior = c(prior(normal(0, 1.5), class = Intercept),
                prior(normal(0, 2), class = b),
                prior(exponential(1), class = sd)),
      iter = 10000, warmup = 8000, chains = 4, cores = 4,
      control = list(adapt_delta = 0.999, max_treedepth = 15),
      seed = 2, file = "Fits/female_fitness.01")

#add_criterion(female_fitness.02, criterion = "waic")

print(female_fitness.01)
##  Family: binomial 
##   Links: mu = logit 
## Formula: Total_red_offspring | trials(Total_offspring) ~ 1 + Evolution_treatment + GFP + Block + (1 | Population) + (1 | Rearing_vial) 
##    Data: female_fitness (Number of observations: 327) 
##   Draws: 4 chains, each with iter = 10000; warmup = 8000; thin = 1;
##          total post-warmup draws = 8000
## 
## Group-Level Effects: 
## ~Population (Number of levels: 12) 
##               Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sd(Intercept)     0.06      0.05     0.00     0.19 1.01      649     1437
## 
## ~Rearing_vial (Number of levels: 70) 
##               Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sd(Intercept)     0.27      0.03     0.22     0.33 1.00     1772     3026
## 
## Population-Level Effects: 
##                                   Estimate Est.Error l-95% CI u-95% CI Rhat
## Intercept                             1.09      0.10     0.91     1.28 1.00
## Evolution_treatmentFemale_limited     0.19      0.10    -0.01     0.39 1.00
## Evolution_treatmentMale_limited       0.16      0.10    -0.03     0.36 1.00
## GFPUBI                               -0.32      0.08    -0.48    -0.16 1.00
## Block2                               -0.58      0.08    -0.75    -0.43 1.00
## Block3                               -0.61      0.08    -0.77    -0.45 1.00
##                                   Bulk_ESS Tail_ESS
## Intercept                             2167     3294
## Evolution_treatmentFemale_limited     2313     2741
## Evolution_treatmentMale_limited       2397     3541
## GFPUBI                                2188     3499
## Block2                                1879     3162
## Block3                                1882     3143
## 
## Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).

Conduct a posterior predictive check to confirm our model is doing what we want it to.

pp_check(female_fitness.01, type = "hist", ndraws = 11, binwidth = 10) +
  theme_minimal() +
  theme(panel.background = element_blank())

The posterior predictive distribution matches our raw data quite well, indicating the model is functioning as we wanted.

\(~\)

Get predictions from the model and present them in a Table

draws <- as_draws_df(female_fitness.01)

draws_female <-
  draws  %>% 
  mutate(`Female-limited` = inv_logit_scaled(b_Intercept + b_Evolution_treatmentFemale_limited),
         `Male-limited` = inv_logit_scaled(b_Intercept + b_Evolution_treatmentMale_limited),
         Control = inv_logit_scaled(b_Intercept)) %>% 
  select(Control, `Female-limited`, `Male-limited`) %>% 
    pivot_longer(cols = c(Control, `Female-limited`, `Male-limited`),
                 names_to = "Evolution_treatment") %>% 
  rename(prop_focal_offspring = value)

draws_female %>% 
  group_by(Evolution_treatment) %>% 
  summarise(`Estimated prop. of offspring produced` = median(prop_focal_offspring),
            `2.5%` = quantile(prop_focal_offspring, probs = 0.025),
            `97.5%` = quantile(prop_focal_offspring, probs = 0.975)) %>% 
  rename(`Evolution treatment` = Evolution_treatment) %>% 
  pander(split.cell = 40, split.table = Inf, round = 3)
Evolution treatment Estimated prop. of offspring produced 2.5% 97.5%
Control 0.749 0.712 0.783
Female-limited 0.784 0.749 0.815
Male-limited 0.778 0.746 0.808
# now find the differences between the control and the sex-limited treatments

# the inv_logit_scaled() function converts the posterior draws onto the response scale 

  draws %>% 
  mutate(p_control =  inv_logit_scaled(b_Intercept),
         p_female = inv_logit_scaled(b_Evolution_treatmentFemale_limited + b_Intercept),
         p_male = inv_logit_scaled(b_Evolution_treatmentMale_limited + b_Intercept),
         `Female-limited` = p_female / p_control,
         `Male-limited` = p_male / p_control) %>% 
  gather(key = `difference comparison`, value = `% difference`) %>% 
  filter(`difference comparison` == c("Female-limited", "Male-limited")) %>% 
  group_by(`difference comparison`)  %>% 
  summarise(`Mean proportion of offspring produced relative to control`  = mean(`% difference`),
            `2.5%` = quantile(`% difference`, probs = 0.025),
            `97.5%` = quantile(`% difference`, probs = 0.975)) %>% 
  rename(`Evolution treatment` = `difference comparison`) %>% 
  pander(split.cell = 40, split.table = Inf, round = 3)
Evolution treatment Mean proportion of offspring produced relative to control 2.5% 97.5%
Female-limited 1.046 0.997 1.097
Male-limited 1.039 0.993 1.091

\(~\)

Male fitness

\(~\)

To estimate the fitness of males carrying each of the three chromosome types, we conducted an experiment very similar to the female fitness assay. However, because male fitness has stronger covariance with fertilisation events than does female fitness, we conducted the male fitness assay with a 1:2 sex ratio (female:male) rather than the 1:1 ratio used in the female assay. This increases the strength of sexual selection and is a more appopriate way to expose differences in fitness between groups of males. As with the females, we calculated fitness as the proportion of red eyed offspring in the vial.

male_fitness.01 <-
  brm(Total_red_offspring | trials(Total_offspring) ~ 1 + Evolution_treatment + GFP + Block + (1|Population) + (1|Rearing_vial),
      data = male_fitness, family = binomial(), 
      prior = c(prior(normal(0, 1.5), class = Intercept),
                prior(normal(0, 2), class = b),
                prior(exponential(1), class = sd)),
      iter = 10000, warmup = 8000, chains = 4, cores = 4,
      control = list(adapt_delta = 0.999, max_treedepth = 15),
      seed = 2, file = "Fits/male_fitness.01")

#add_criterion(male_fitness.02, criterion = "waic")

print(male_fitness.01)
##  Family: binomial 
##   Links: mu = logit 
## Formula: Total_red_offspring | trials(Total_offspring) ~ 1 + Evolution_treatment + GFP + Block + (1 | Population) + (1 | Rearing_vial) 
##    Data: male_fitness (Number of observations: 360) 
##   Draws: 4 chains, each with iter = 10000; warmup = 8000; thin = 1;
##          total post-warmup draws = 8000
## 
## Group-Level Effects: 
## ~Population (Number of levels: 12) 
##               Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sd(Intercept)     0.29      0.15     0.05     0.63 1.00     1284     1796
## 
## ~Rearing_vial (Number of levels: 72) 
##               Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sd(Intercept)     0.62      0.07     0.51     0.76 1.00     2655     4566
## 
## Population-Level Effects: 
##                                   Estimate Est.Error l-95% CI u-95% CI Rhat
## Intercept                             0.66      0.26     0.16     1.16 1.00
## Evolution_treatmentFemale_limited     0.13      0.29    -0.43     0.69 1.00
## Evolution_treatmentMale_limited       0.27      0.29    -0.33     0.82 1.00
## GFPUBI                               -0.07      0.23    -0.54     0.40 1.00
## Block2                                0.92      0.18     0.56     1.28 1.00
## Block3                                0.05      0.18    -0.30     0.39 1.00
##                                   Bulk_ESS Tail_ESS
## Intercept                             5450     5236
## Evolution_treatmentFemale_limited     5534     4821
## Evolution_treatmentMale_limited       5868     5011
## GFPUBI                                6426     5062
## Block2                                4454     5090
## Block3                                4342     4641
## 
## Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).

Conduct the posterior predictive check…

pp_check(male_fitness.01, type = "hist", ndraws = 11, binwidth = 10) +
  theme_minimal() +
  theme(panel.background = element_blank())

Get predictions from the model and present them in a Table

draws_m <- as_draws_df(male_fitness.01)

draws_male <-
  draws_m  %>% 
  mutate(`Female-limited` = inv_logit_scaled(b_Intercept + b_Evolution_treatmentFemale_limited),
         `Male-limited` = inv_logit_scaled(b_Intercept + b_Evolution_treatmentMale_limited),
         Control = inv_logit_scaled(b_Intercept)) %>% 
  select(Control, `Female-limited`, `Male-limited`) %>% 
    pivot_longer(cols = c(Control, `Female-limited`, `Male-limited`),
                 names_to = "Evolution_treatment") %>% 
  rename(prop_focal_offspring = value)

draws_male %>% 
  group_by(Evolution_treatment) %>% 
  summarise(`Estimated prop. of offspring sired` = median(prop_focal_offspring),
            `2.5%` = quantile(prop_focal_offspring, probs = 0.025),
            `97.5%` = quantile(prop_focal_offspring, probs = 0.975)) %>% 
  rename(`Evolution treatment` = Evolution_treatment) %>% 
  pander(split.cell = 40, split.table = Inf, round = 3)
Evolution treatment Estimated prop. of offspring sired 2.5% 97.5%
Control 0.659 0.54 0.761
Female-limited 0.686 0.576 0.782
Male-limited 0.716 0.6 0.807
# now find the differences between the control and the sex-limited Evolution_treatments

# the inv_logit_scaled() function converts the posterior draws onto the response scale 

draws_m %>% 
  mutate(p_control =  inv_logit_scaled(b_Intercept),
         p_female = inv_logit_scaled(b_Evolution_treatmentFemale_limited + b_Intercept),
         p_male = inv_logit_scaled(b_Evolution_treatmentMale_limited + b_Intercept),
         `Female-limited` = p_female / p_control,
         `Male-limited` = p_male / p_control) %>% 
  gather(key = `difference comparison`, value = `% difference`) %>% 
  filter(`difference comparison` == c("Female-limited", "Male-limited")) %>% 
  group_by(`difference comparison`)  %>% 
  summarise(`Mean proportion of offspring sired relative to control`  = mean(`% difference`),
            `2.5%` = quantile(`% difference`, probs = 0.025),
            `97.5%` = quantile(`% difference`, probs = 0.975)) %>% 
  rename(`Evolution treatment` = `difference comparison`) %>% 
  pander(split.cell = 40, split.table = Inf, round = 3)
Evolution treatment Mean proportion of offspring sired relative to control 2.5% 97.5%
Female-limited 1.047 0.872 1.255
Male-limited 1.093 0.906 1.304

Building Figure 1

# female plots

f_1 <-
  draws_female %>% 
  ggplot(aes(Evolution_treatment, prop_focal_offspring)) + 
  stat_eye(aes(fill = Evolution_treatment), .width = c(0.66, 0.95), alpha = 1) + # width indicates the uncertainty intervals: here we have 66% and 95% intervals
  scale_fill_manual(values = met.brewer("Hiroshige", 3)) +
  scale_y_continuous("Female fitness\n(proportion of offspring produced)",
                     breaks = c(0.4, 0.6, 0.8)) +
  coord_cartesian(ylim = c(0.4, 1)) +
  xlab(NULL) +
  theme_bw() + 
  theme(legend.position = "none",
        panel.grid.minor = element_blank())

f_2 <-
  draws %>% 
  mutate(`Female-limited` = b_Evolution_treatmentFemale_limited,
         `Male-limited` = b_Evolution_treatmentMale_limited) %>% 
  gather(key = parameter, value = logodds) %>% 
  filter(parameter == c("Female-limited", "Male-limited")) %>%
  as_tibble() %>% 
  
  ggplot(aes(parameter, logodds)) + 
  stat_halfeye(aes(fill = parameter), .width = c(0.66, 0.95)) + # width indicates the uncertainty intervals: here we have 66% and 95% intervals
  scale_fill_manual(values = c("Female-limited" = "#ffd06f", "Male-limited" = "#72bcd5")) + 
  coord_flip(ylim = c(-1, 1)) +
  geom_hline(yintercept = 0, linetype = 2) +
  scale_y_continuous(breaks = c(-1, 0, 1)) +
  xlab(NULL) +
  ylab(NULL) +
  theme_bw() + 
  theme(legend.position = "none",
        panel.grid.minor = element_blank())

# male plots

f_3 <-
  draws_male %>% 
  ggplot(aes(Evolution_treatment, prop_focal_offspring)) + 
  stat_eye(aes(fill = Evolution_treatment), .width = c(0.66, 0.95), alpha = 1) + # width indicates the uncertainty intervals: here we have 66% and 95% intervals
  scale_fill_manual(values = met.brewer("Hiroshige", 3)) +
  scale_y_continuous("Male fitness\n(proportion of offspring sired)",
                     breaks = c(0.4, 0.6, 0.8)) +
  coord_cartesian(ylim = c(0.4, 1)) +
  xlab("Evolutionary history") +
  theme_bw() + 
  theme(legend.position = "none",
        panel.grid.minor = element_blank())

f_4 <-
  draws_m %>% 
  mutate(`Female-limited` = b_Evolution_treatmentFemale_limited,
         `Male-limited` = b_Evolution_treatmentMale_limited) %>% 
  gather(key = parameter, value = logodds) %>% 
  filter(parameter == c("Female-limited", "Male-limited")) %>%
  as_tibble() %>% 
  #mutate(parameter =factor(parameter, levels=c("SD-Mad", "SD-72", "SD-5"))) %>%
  
  ggplot(aes(parameter, logodds)) + 
  stat_halfeye(aes(fill = parameter), .width = c(0.66, 0.95)) + # width indicates the uncertainty intervals: here we have 66% and 95% intervals
  scale_fill_manual(values = c("Female-limited" = "#ffd06f", "Male-limited" = "#72bcd5")) + 
  coord_flip(ylim = c(-1, 1)) +
  geom_hline(yintercept = 0, linetype = 2) +
  scale_y_continuous(breaks = c(-1, 0, 1)) +
  xlab(NULL) +
  ylab("Log-odds mean difference from control") +
  theme_bw() + 
  theme(legend.position = "none",
        panel.grid.minor = element_blank())


(f_1 + f_2) /(f_3 + f_4)

Figure 1: a shows the estimated mean female fitness for flies carrying autosomes that had previously experienced unconstrained inheritance (control), female-limited inheritance or male-limited inheritance. b shows the log-odds mean difference in means between the sex-limited treatments and the control evolutionary treatment. c and d depict the same things as a and b, except for estimated mean male fitness.

LS0tCnRpdGxlOiAiRXhwZXJpbWVudGFsIGVuZm9yY2VtZW50IG9mIHNleC1saW1pdGVkIGFkYXB0YXRpb24iCmF1dGhvcjogIlRob21hcyBLZWFuZXkiCiNiaWJsaW9ncmFwaHk6ICJzdXBwX3JlZmVyZW5jZXMuYmliIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgZGVwdGg6IDEKICAgIG51bWJlcl9zZWN0aW9uczogbm8KICAgIHRoZW1lOiB5ZXRpCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKZWRpdG9yX29wdGlvbnM6CiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUKLS0tCgoKCmBgYHtyfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBjYWNoZSA9IEZBTFNFKQpgYGAKCiMgU2V0dXAgZm9yIGFuYWx5c2lzCgojIyBMb2FkIHBhY2thZ2VzCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpICMgdGlkeSBzdHlsZSBjb2RpbmcKbGlicmFyeShicm1zKSAjIEJheWVzaWFuIG1vZGVscwpsaWJyYXJ5KGxvbykgIyB0byB1c2UgaW5mb3JtYXRpb24gY3JpdGVyaWEgaW4gYnJtcyBtb2RlbHMKbGlicmFyeSh0aWR5YmF5ZXMpICMgQmF5ZXNpYW4gYWVzdGhldGljcwpsaWJyYXJ5KE1ldEJyZXdlcikgIyBjb2xvdXJzCmxpYnJhcnkoa2FibGVFeHRyYSkgIyB0YWJsZXMKbGlicmFyeShwYXRjaHdvcmspICMgcHV0dGluZyBwbG90cyB0b2dldGhlcgpsaWJyYXJ5KERUKSAjIGZvciBzZWFyY2gtIGFuZCBzYXZlYWJsZSB0YWJsZXMKbGlicmFyeShwYW5kZXIpICMgZm9yIHNpbXBsZXIgdGFibGVzCmxpYnJhcnkoZ2dkYWcpICMgdG8gdmlzdWFsaXNlIGNhc3VhbCByZWxhdGlvbnNoaXBzCmBgYAoKIyMgTG9hZCBpbiB0aGUgZGF0YSAKCiR+JAoKYGBge3J9CgpmaXRuZXNzX2RhdGEgPC0gcmVhZF9jc3YoImRhdGEvU0xDX2ZpdG5lc3NfZGF0YS5jc3YiKSAlPiUgCiAgbXV0YXRlKEZpdG5lc3NfdmlhbF9JRCA9IGFzLmZhY3RvcihGaXRuZXNzX3ZpYWxfSUQpLAogICAgICAgICBCbG9jayA9IGFzLmZhY3RvcihCbG9jayksCiAgICAgICAgIFBvcHVsYXRpb24gPSBhcy5mYWN0b3IoUG9wdWxhdGlvbiksCiAgICAgICAgIFRyZWF0bWVudCA9IGFzLmZhY3RvcihUcmVhdG1lbnQpLAogICAgICAgICBHRlAgPSBhcy5mYWN0b3IoR0ZQKSwKICAgICAgICAgU2V4ID0gYXMuZmFjdG9yKFNleCksCiAgICAgICAgIFJlYXJpbmdfdmlhbCA9IGFzLmZhY3RvcihSZWFyaW5nX3ZpYWwpLAogICAgICAgICBTZXggPSBhcy5mYWN0b3IoU2V4KSwKICAgICAgICAgVG90YWxfcmVkX29mZnNwcmluZyA9IFJlZF9mZW1hbGVfb2Zmc3ByaW5nICsgUmVkX21hbGVfb2Zmc3ByaW5nLAogICAgICAgICBUb3RhbF9id19vZmZzcHJpbmcgPSBid19mZW1hbGVfb2Zmc3ByaW5nICsgYndfbWFsZV9vZmZzcHJpbmcsCiAgICAgICAgIFRvdGFsX29mZnNwcmluZyA9IFRvdGFsX3JlZF9vZmZzcHJpbmcgKyBUb3RhbF9id19vZmZzcHJpbmcpICU+JSAKICByZW5hbWUoRXZvbHV0aW9uX3RyZWF0bWVudCA9IFRyZWF0bWVudCkKCiMgQ3JlYXRlIGEgZnVuY3Rpb24gdG8gYnVpbGQgSFRNTCBzZWFyY2hhYmxlIHRhYmxlcwoKbXlfZGF0YV90YWJsZSA8LSBmdW5jdGlvbihkZil7CiAgZGF0YXRhYmxlKAogICAgZGYsIHJvd25hbWVzPUZBTFNFLAogICAgYXV0b0hpZGVOYXZpZ2F0aW9uID0gVFJVRSwKICAgIGV4dGVuc2lvbnMgPSBjKCJTY3JvbGxlciIsICAiQnV0dG9ucyIpLAogICAgb3B0aW9ucyA9IGxpc3QoCiAgICAgIGRvbSA9ICdCZnJ0aXAnLAogICAgICBkZWZlclJlbmRlcj1UUlVFLAogICAgICBzY3JvbGxYPVRSVUUsIHNjcm9sbFk9NDAwLAogICAgICBzY3JvbGxDb2xsYXBzZT1UUlVFLAogICAgICBidXR0b25zID0KICAgICAgICBsaXN0KCdwYWdlTGVuZ3RoJywgJ2NvbHZpcycsICdjc3YnLCBsaXN0KAogICAgICAgICAgZXh0ZW5kID0gJ3BkZicsCiAgICAgICAgICBwYWdlU2l6ZSA9ICdBNCcsCiAgICAgICAgICBvcmllbnRhdGlvbiA9ICdsYW5kc2NhcGUnLAogICAgICAgICAgZmlsZW5hbWUgPSAnZml0bmVzc19kYXRhJykpLAogICAgICBwYWdlTGVuZ3RoID0gNjkyCiAgICApCiAgKQp9CgoKbXlfZGF0YV90YWJsZShmaXRuZXNzX2RhdGEgJT4lIHNlbGVjdCgtQ29tbWVudCkpCgpgYGAKCioqQ29sdW1uIGV4cGxhbmF0aW9ucyoqCgpGaXRuZXNzX3ZpYWxfSUQ6IGEgdW5pcXVlIGlkZW50aWZpZXIgZm9yIGVhY2ggcmVwbGljYXRlIG9mIHRoZSBmaXRuZXNzIGFzc2F5cy4KCkJsb2NrOiB0aGUgZXhwZXJpbWVudCB3YXMgcnVuIGluIHRocmVlIGRpc3RpbmN0IGJsb2NrcywgdXNpbmcgZmxpZXMgZnJvbSBzZXBhcmF0ZSBnZW5lcmF0aW9ucy4KClBvcHVsYXRpb246IHdlIG1lYXN1cmVkIHRoZSBmaXRuZXNzIG9mIGZsaWVzIGZyb20gMTIgaW5kZXBlbmRlbnQgcG9wdWxhdGlvbnMgdGhhdCBoYXMgdW5kZXJnb25lIGV4cGVyaW1lbnRhbCBldm9sdXRpb24uCgpFdm9sdXRpb25fdHJlYXRtZW50OiB0aGUgcG9wdWxhdGlvbnMgaGFkIGJlZW4gZXhwb3NlZCB0byBvbmUgb2YgdGhyZWUgZXZvbHV0aW9uYXJ5IGNvbmRpdGlvbnMgZm9yIDIwIGdlbmVyYXRpb25zOiBhIGZlbWFsZS1saW1pdGVkIHJlc3BvbnNlIHRvIHNlbGVjdGlvbiwgYSBtYWxlLWxpbWl0ZWQgcmVzcG9uc2UgYW5kIGEgY29udHJvbCBjb25kaXRpb24gd2hlcmUgdGhlIGV2b2x1dGlvbmFyeSByZXNwb25zZSB3YXMgdW5jb25zdHJhaW5lZC4KCkdGUDogdGhlIEdGUCBtYXJrZXIgY2FycmllZCBieSB0aGUgcG9wdWxhdGlvbi4gVUJJIGluZGljYXRlcyB0aGUgcHJlc2VuY2Ugb2YgYSB0cmFuc2dlbmUgdGhhdCBlbmNvZGVzIHViaXF1aXRvdXMgZXhwcmVzc2lvbiBvZiBHRlAsIHdoaWxlIDN4UCBpbmRpY2F0ZXMgdGhlIHByZXNlbmNlIG9mIGEgZGlmZmVyZW50IHRyYW5zZ2VuZSB0aGF0IGVuY29kZXMgdGhlIGV4cHJlc3Npb24gb2YgR0ZQIGluIHRoZSBvY2VsbGkuIAoKU2V4OiB0aGUgc2V4IG9mIHRoZSBpbmRpdmlkdWFscyB0aGF0IHdlIHdlcmUgbWVhc3VyaW5nIHRoZSBmaXRuZXNzIG9mLgoKUmVhcmluZ192aWFsOiB0aGUgdmlhbCB0aGUgZmxpZXMgZGV2ZWxvcGVkIGluLiBUaGlzIHZhcmlhYmxlIGlzIGluY2x1ZGVkIHRvIGNhcHR1cmUgdmFyaWF0aW9uIGV4cGxhaW5lZCBieSB0aGUgcmVhcmluZyBlbnZpcm9ubWVudCBlLmcuIHNtYWxsIGRpZmZlcmVuY2VzIGluIGZvb2QgbW9pc3R1cmUgY29udGVudCBvciBxdWFudGl0eS4gTm90ZSB0aGF0IGZlbWFsZXMgYW5kIG1hbGVzIGNhbiBoYXZlIHRoZSBzYW1lIHJlYXJpbmcgdmlhbC4KClJlZF9mZW1hbGVfb2Zmc3ByaW5nOiB0aGUgbnVtYmVyIG9mIGFkdWx0IGZlbWFsZSBvZmZzcHJpbmcgc2lyZWQvcHJvZHVjZWQgYnkgZmxpZXMgc291cmNlZCBmcm9tIG9uZSBvZiB0aGUgMTIgcG9wdWxhdGlvbnMuCgpSZWRfbWFsZV9vZmZzcHJpbmc6IHRoZSBudW1iZXIgb2YgYWR1bHQgbWFsZSBvZmZzcHJpbmcgc2lyZWQvcHJvZHVjZWQgYnkgZmxpZXMgc291cmNlZCBmcm9tIG9uZSBvZiB0aGUgMTIgcG9wdWxhdGlvbnMuCgpid19mZW1hbGVfb2Zmc3ByaW5nOiB0aGUgbnVtYmVyIG9mIGFkdWx0IGZlbWFsZSBvZmZzcHJpbmcgc2lyZWQvcHJvZHVjZWQgYnkgdGhlIGNvbXBldGl0b3IgZmxpZXMgaW4gb3VyIGZpdG5lc3MgYXNzYXkuIF9id18gaXMgYSByZWNlc3NpdmUgYWxsZWxlIHRoYXQgZW5jb2RlcyBicm93biBleWUgY29sb3VyLgoKYndfbWFsZV9vZmZzcHJpbmc6IHRoZSBudW1iZXIgb2YgYWR1bHQgbWFsZSBvZmZzcHJpbmcgc2lyZWQvcHJvZHVjZWQgYnkgdGhlIGNvbXBldGl0b3IgZmxpZXMgaW4gb3VyIGZpdG5lc3MgYXNzYXkuIF9id18gaXMgYSByZWNlc3NpdmUgYWxsZWxlIHRoYXQgZW5jb2RlcyBicm93biBleWUgY29sb3VyLgoKVG90YWxfcmVkX29mZnNwcmluZzogdGhlIHRvdGFsIG51bWJlciAoc2V4ZXMgcG9vbGVkKSBvZiBhZHVsdCBvZmZzcHJpbmcgc2lyZWQvcHJvZHVjZWQgYnkgZmxpZXMgc291cmNlZCBmcm9tIG9uZSBvZiB0aGUgMTIgcG9wdWxhdGlvbnMuCgpUb3RhbF9id19vZmZzcHJpbmc6IHRoZSB0b3RhbCBudW1iZXIgKHNleGVzIHBvb2xlZCkgb2YgYWR1bHQgb2Zmc3ByaW5nIHNpcmVkL3Byb2R1Y2VkIGJ5IGNvbXBldGl0b3IgZmxpZXMuCgpUb3RhbF9vZmZzcHJpbmc6IHRoZSB0b3RhbCBudW1iZXIgKHNleGVzIGFuZCBleWUgY29sb3VycyBwb29sZWQpIG9mIGFkdWx0IG9mZnNwcmluZyBjb3VudGVkIGluIGVhY2ggdmlhbC4KCgokfiQKCiMgTW9kZWxsaW5nIGFwcHJvYWNoCgokfiQKCkZlbWFsZSBhbmQgbWFsZSBmaXRuZXNzIGFyZSBmdW5kYW1lbnRhbGx5IGRpZmZlcmVudCBjb25jZXB0cyAvIHRyYWl0cy4gVGhlcmUgYXJlIGFsc28gc2V2ZXJhbCBkaWZmZXJlbmNlcyBiZXR3ZWVuIG91ciBmZW1hbGUgYW5kIG1hbGUgZml0bmVzcyBhc3NheXMuIFRoZSBtYWpvciBkaWZmZXJlbmNlIGlzIHRoYXQgdGhlIG1hbGUgYXNzYXkgY29udGFpbnMgaGFsZiB0aGUgbnVtYmVyIG9mIGZlbWFsZXMgaW4gYW55IGdpdmVuIHZpYWwgdGhhbiBkb2VzIHRoZSBmZW1hbGUgYXNzYXkuIFRoZSBsb2dpYyBiZWhpbmQgdGhpcyBkZXNpZ24gY2hvaWNlIGlzIHRoYXQgc2V4dWFsbHkgc2VsZWN0ZWQgcHJvY2Vzc2VzIGFyZSBhIG1vcmUgaW1wb3J0YW50IGRldGVybWluYW50IG9mIG1hbGUgZml0bmVzcyB0aGFuIHRoZXkgYXJlIGZlbWFsZSBmaXRuZXNzLCBzbyBhbnkgZml0bmVzcyBkaWZmZXJlbmNlcyBtYXkgb25seSBiZSBvYnNlcnZlZCB3aGVuIGNvbXBldGl0aW9uIGZvciBmZXJ0aWxpc2F0aW9ucyBpcyBoaWdoLiAKCkZvciB0aGVzZSByZWFzb25zLCB3ZSBjaG9vc2UgdG8gc3BsaXQgdGhlIGRhdGEgdXAgYW5kIG1vZGVsIHRoZW0gc2VwYXJhdGVseS4KCmBgYHtyfQpmZW1hbGVfZml0bmVzcyA8LSAKICBmaXRuZXNzX2RhdGEgJT4lCiAgZmlsdGVyKFNleCA9PSAiRmVtYWxlIikKCm1hbGVfZml0bmVzcyA8LSAKICBmaXRuZXNzX2RhdGEgJT4lCiAgZmlsdGVyKFNleCA9PSAiTWFsZSIpCiAgCmBgYAoKKipGaXhlZCBlZmZlY3RzKioKCmBCbG9ja2A6IGZpdG5lc3MgbWlnaHQgZGlmZmVyIGJldHdlZW4gdGhlIHRocmVlIGRpc3RpbmN0IGJsb2NrcyB3ZSBzcGxpdCBvdXIgZXhwZXJpbWVudCB1cCBpbnRvLiBCbG9ja3MgZGlmZmVyZWQgdGVtcG9yYWxseSwgdXNlZCBmbGllcyBmcm9tIGRpZmZlcmVudCBnZW5lcmF0aW9ucyBhbmQgZGlmZmVyZW50IGJhdGNoZXMgb2YgZm9vZC4gSXQgaXMgYWxzbyBwb3NzaWJsZSB0aGF0IHRoZXJlIHdlcmUgbWlub3IgZmx1Y3R1YXRpb25zIGluIHRoZSBsaWdodGluZyBhbmQgdGVtcGVyYXR1cmUgZW52aXJvbm1lbnQgZXhwZXJpZW5jZWQgZHVyaW5nIGRldmVsb3BtZW50IGJldHdlZW4gYmxvY2tzLiBFYWNoIG9mIHRoZXNlIHZhcmlhYmxlcyBtYXkgaW50cm9kdWNlIHZhcmlhdGlvbiBpbnRvIG91ciBmaXRuZXNzIG1lYXN1cmVtZW50cywgdGhhdCBjYW4gYmUgYWNjb3VudGVkIGZvciBieSBpbmNsdWRpbmcgdGhlIGBCbG9ja2AgdmFyaWFibGUgaW4gb3VyIG1vZGVsLgoKYEdGUGA6IGl0IGlzIHBvc3NpYmxlIHRoYXQgZml0bmVzcyBtYXkgYmUgYWZmZWN0ZWQgYnkgdGhlIEdGUCB0cmFuc2dlbmUgY2FycmllZCBieSBlYWNoIHBvcHVsYXRpb24uIEZvciBleGFtcGxlLCBvbmUgY291bGQgaW1hZ2luZSB0aGF0IGFueSB1bmludGVuZGVkIGZpdG5lc3MgZWZmZWN0cyBvZiBhIHRyYW5zZ2VuZSBtaWdodCBiZSBvZiBncmVhdGVyIG1hZ25pdHVkZSBpZiBpdCBpcyBleHByZXNzZWQgaW4gYSBsYXJnZXIgcHJvcG9ydGlvbiBvZiB0aXNzdWVzLCBhcyBpcyB0aGUgY2FzZSBmb3IgdGhlIF9VQklfIHRyYW5zZ2VuZSB2ZXJzdXMgdGhlIF8zeFBfIHRyYW5zZ2VuZS4gTm90ZSB0aGF0IGVhY2ggR0ZQIHR5cGUgaXMgY2FycmllZCBieSBhbiBlcXVhbCBudW1iZXIgb2YgcG9wdWxhdGlvbnMgZnJvbSBlYWNoIG9mIHRoZSB0aHJlZSBldm9sdXRpb25hcnkgdHJlYXRtZW50cy4KCmBFdm9sdXRpb25fdHJlYXRtZW50YDogdGhpcyBpcyB0aGUgZXZvbHV0aW9uIGNvbmRpdGlvbiB0aGF0IHBvcHVsYXRpb25zIHdlcmUgc3ViamVjdCB0byBmb3IgMjAgZ2VuZXJhdGlvbnMuIFRoZXJlIGFyZSB0aHJlZSBsZXZlbHM6IHBvcHVsYXRpb25zIGNhcnJ5aW5nIGZlbWFsZS1hZGFwdGVkIGNocm9tb3NvbWVzLCBwb3B1bGF0aW9ucyBjb250YWluaW5nIG1hbGUtYWRhcHRlZCBjaHJvbW9zb21lcyBhbmQgcG9wdWxhdGlvbnMgY2FycnlpbmcgY29udHJvbCBjaHJvbW9zb21lcyB0aGF0IGhhdmUgZXhwZXJpZW5jZWQgYW4gdW5saW1pdGVkIHJlc3BvbnNlIHRvIHNlbGVjdGlvbi4gVGhpcyB2YXJpYWJsZSBpcyBjZW50cmFsIHRvIG91ciBoeXBvdGhlc2lzLgoKKipSYW5kb20gZWZmZWN0cyoqCgpgUmVhcmluZ192aWFsYDogdGhlIHZpYWwgaW5kaXZpZHVhbCBmbGllcyBkZXZlbG9wZWQgd2l0aGluIG1heSBpbnRyb2R1Y2UgZnVydGhlciB2YXJpYXRpb24gaW50byBvdXIgcmVzcG9uc2UgdmFyaWFibGUuIExpa2UgYEJsb2NrYCB0aGlzIHZhcmlhYmxlIGNvbnRyb2xzIGZvciBtaWNyby1lbnZpcm9ubWVudGFsIHZhcmlhdGlvbi4KCmBQb3B1bGF0aW9uYDogb3VyIGRlc2lnbiBjb250YWluZWQgMTIgaW5kZXBlbmRlbnQgcG9wdWxhdGlvbnMgb2YgY2hyb21vc29tZXMgdGhhdCBvcmlnaW5hdGVkIGZyb20gYSBzaW5nbGUgb3V0YnJlZCBsYWJvcmF0b3J5IGZseSBwb3B1bGF0aW9uLiBUaGUgcG9wdWxhdGlvbnMgd2VyZSBzcGxpdCBhbmQgY2hyb21vc29tZXMgZnJvbSBlYWNoIHdlcmUgc3ViamVjdGVkIHRvIG9uZSBvZiB0aGUgdGhyZWUgZXZvbHV0aW9uIHRyZWF0bWVudHMgZm9yIDIwIGdlbmVyYXRpb25zLiA0IHBvcHVsYXRpb25zIGV4cGVyaWVuY2VkIGEgZmVtYWxlLWxpbWl0ZWQgcmVzcG9uc2UgdG8gc2VsZWN0aW9uLCA0IGEgbWFsZS1saW1pdGVkIHJlc3BvbnNlIGFuZCA0IGFuIHVubGltaXRlZCByZXNwb25zZS4gCgokfiQKCiMgRmVtYWxlIGZpdG5lc3MKCiR+JAoKVG8gZXN0aW1hdGUgdGhlIGZpdG5lc3Mgb2YgZmVtYWxlcyBjYXJyeWluZyBlYWNoIG9mIHRoZSB0aHJlZSBjaHJvbW9zb21lIHR5cGVzLCB3ZSBwbGFjZWQgdGhyZWUgZXhwZXJpbWVudGFsIGZlbWFsZXMgaW50byBhIHllYXN0ZWQgdmlhbCB3aXRoIHRocmVlIGZlbWFsZSBjb21wZXRpdG9ycyB0aGF0IGNhcnJpZWQgdGhlIF9id18gbXV0YXRpb24uIFdlIHRoZW4gaW50cm9kdWNlZCBzaXggbWFsZXMgdGhhdCBhbHNvIGNhcnJpZWQgdGhlIF9id18gbXV0YXRpb24uIFdlIGFsbG93ZWQgdGhlbSB0byBtYXRlIGFuZCBvdmlwb3NpdCBmb3IgdGhyZWUgZGF5cywgdGhlbiByZW1vdmVkIGFsbCBhZHVsdHMgZnJvbSB0aGUgdmlhbC4gMTIgZGF5cyBsYXRlciB3ZSBjb3VudGVkIGFsbCBvZiB0aGUgYWR1bHQgcHJvZ2VueSBpbiB0aGUgdmlhbCBhbmQgc2NvcmVkIHRoZW0gZm9yIGV5ZS1jb2xvdXIuIFByb2dlbnkgd2l0aCByZWQgZXllcyB3ZXJlIHByb2R1Y2VkIGJ5IHRoZSBleHBlcmltZW50YWwgZmVtYWxlcyAoIF9id18gaXMgcmVjZXNzaXZlKSBhbmQgcHJvZ2VueSB3aXRoIGJyb3duIGV5ZXMgd2VyZSBwcm9kdWNlZCBieSB0aGUgY29tcGV0aXRvciBmZW1hbGVzLiBXZSBjYWxjdWxhdGVkIGZpdG5lc3MgYXMgdGhlIHByb3BvcnRpb24gb2YgcmVkIGV5ZWQgb2Zmc3ByaW5nIGluIHRoZSB2aWFsLiAKCiR+JAoKCmBgYHtyfQpmZW1hbGVfZml0bmVzcy4wMSA8LQogIGJybShUb3RhbF9yZWRfb2Zmc3ByaW5nIHwgdHJpYWxzKFRvdGFsX29mZnNwcmluZykgfiAxICsgRXZvbHV0aW9uX3RyZWF0bWVudCArIEdGUCArIEJsb2NrICsgKDF8UG9wdWxhdGlvbikgKyAoMXxSZWFyaW5nX3ZpYWwpLAogICAgICBkYXRhID0gZmVtYWxlX2ZpdG5lc3MsIGZhbWlseSA9IGJpbm9taWFsKCksIAogICAgICBwcmlvciA9IGMocHJpb3Iobm9ybWFsKDAsIDEuNSksIGNsYXNzID0gSW50ZXJjZXB0KSwKICAgICAgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAyKSwgY2xhc3MgPSBiKSwKICAgICAgICAgICAgICAgIHByaW9yKGV4cG9uZW50aWFsKDEpLCBjbGFzcyA9IHNkKSksCiAgICAgIGl0ZXIgPSAxMDAwMCwgd2FybXVwID0gODAwMCwgY2hhaW5zID0gNCwgY29yZXMgPSA0LAogICAgICBjb250cm9sID0gbGlzdChhZGFwdF9kZWx0YSA9IDAuOTk5LCBtYXhfdHJlZWRlcHRoID0gMTUpLAogICAgICBzZWVkID0gMiwgZmlsZSA9ICJGaXRzL2ZlbWFsZV9maXRuZXNzLjAxIikKCiNhZGRfY3JpdGVyaW9uKGZlbWFsZV9maXRuZXNzLjAyLCBjcml0ZXJpb24gPSAid2FpYyIpCgpwcmludChmZW1hbGVfZml0bmVzcy4wMSkKYGBgCgpDb25kdWN0IGEgcG9zdGVyaW9yIHByZWRpY3RpdmUgY2hlY2sgdG8gY29uZmlybSBvdXIgbW9kZWwgaXMgZG9pbmcgd2hhdCB3ZSB3YW50IGl0IHRvLgoKYGBge3J9CnBwX2NoZWNrKGZlbWFsZV9maXRuZXNzLjAxLCB0eXBlID0gImhpc3QiLCBuZHJhd3MgPSAxMSwgYmlud2lkdGggPSAxMCkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgpUaGUgcG9zdGVyaW9yIHByZWRpY3RpdmUgZGlzdHJpYnV0aW9uIG1hdGNoZXMgb3VyIHJhdyBkYXRhIHF1aXRlIHdlbGwsIGluZGljYXRpbmcgdGhlIG1vZGVsIGlzIGZ1bmN0aW9uaW5nIGFzIHdlIHdhbnRlZC4KCiR+JAoKR2V0IHByZWRpY3Rpb25zIGZyb20gdGhlIG1vZGVsIGFuZCBwcmVzZW50IHRoZW0gaW4gYSBUYWJsZQoKYGBge3J9CgpkcmF3cyA8LSBhc19kcmF3c19kZihmZW1hbGVfZml0bmVzcy4wMSkKCmRyYXdzX2ZlbWFsZSA8LQogIGRyYXdzICAlPiUgCiAgbXV0YXRlKGBGZW1hbGUtbGltaXRlZGAgPSBpbnZfbG9naXRfc2NhbGVkKGJfSW50ZXJjZXB0ICsgYl9Fdm9sdXRpb25fdHJlYXRtZW50RmVtYWxlX2xpbWl0ZWQpLAogICAgICAgICBgTWFsZS1saW1pdGVkYCA9IGludl9sb2dpdF9zY2FsZWQoYl9JbnRlcmNlcHQgKyBiX0V2b2x1dGlvbl90cmVhdG1lbnRNYWxlX2xpbWl0ZWQpLAogICAgICAgICBDb250cm9sID0gaW52X2xvZ2l0X3NjYWxlZChiX0ludGVyY2VwdCkpICU+JSAKICBzZWxlY3QoQ29udHJvbCwgYEZlbWFsZS1saW1pdGVkYCwgYE1hbGUtbGltaXRlZGApICU+JSAKICAgIHBpdm90X2xvbmdlcihjb2xzID0gYyhDb250cm9sLCBgRmVtYWxlLWxpbWl0ZWRgLCBgTWFsZS1saW1pdGVkYCksCiAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiRXZvbHV0aW9uX3RyZWF0bWVudCIpICU+JSAKICByZW5hbWUocHJvcF9mb2NhbF9vZmZzcHJpbmcgPSB2YWx1ZSkKCmRyYXdzX2ZlbWFsZSAlPiUgCiAgZ3JvdXBfYnkoRXZvbHV0aW9uX3RyZWF0bWVudCkgJT4lIAogIHN1bW1hcmlzZShgRXN0aW1hdGVkIHByb3AuIG9mIG9mZnNwcmluZyBwcm9kdWNlZGAgPSBtZWRpYW4ocHJvcF9mb2NhbF9vZmZzcHJpbmcpLAogICAgICAgICAgICBgMi41JWAgPSBxdWFudGlsZShwcm9wX2ZvY2FsX29mZnNwcmluZywgcHJvYnMgPSAwLjAyNSksCiAgICAgICAgICAgIGA5Ny41JWAgPSBxdWFudGlsZShwcm9wX2ZvY2FsX29mZnNwcmluZywgcHJvYnMgPSAwLjk3NSkpICU+JSAKICByZW5hbWUoYEV2b2x1dGlvbiB0cmVhdG1lbnRgID0gRXZvbHV0aW9uX3RyZWF0bWVudCkgJT4lIAogIHBhbmRlcihzcGxpdC5jZWxsID0gNDAsIHNwbGl0LnRhYmxlID0gSW5mLCByb3VuZCA9IDMpCgojIG5vdyBmaW5kIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSBjb250cm9sIGFuZCB0aGUgc2V4LWxpbWl0ZWQgdHJlYXRtZW50cwoKIyB0aGUgaW52X2xvZ2l0X3NjYWxlZCgpIGZ1bmN0aW9uIGNvbnZlcnRzIHRoZSBwb3N0ZXJpb3IgZHJhd3Mgb250byB0aGUgcmVzcG9uc2Ugc2NhbGUgCgogIGRyYXdzICU+JSAKICBtdXRhdGUocF9jb250cm9sID0gIGludl9sb2dpdF9zY2FsZWQoYl9JbnRlcmNlcHQpLAogICAgICAgICBwX2ZlbWFsZSA9IGludl9sb2dpdF9zY2FsZWQoYl9Fdm9sdXRpb25fdHJlYXRtZW50RmVtYWxlX2xpbWl0ZWQgKyBiX0ludGVyY2VwdCksCiAgICAgICAgIHBfbWFsZSA9IGludl9sb2dpdF9zY2FsZWQoYl9Fdm9sdXRpb25fdHJlYXRtZW50TWFsZV9saW1pdGVkICsgYl9JbnRlcmNlcHQpLAogICAgICAgICBgRmVtYWxlLWxpbWl0ZWRgID0gcF9mZW1hbGUgLyBwX2NvbnRyb2wsCiAgICAgICAgIGBNYWxlLWxpbWl0ZWRgID0gcF9tYWxlIC8gcF9jb250cm9sKSAlPiUgCiAgZ2F0aGVyKGtleSA9IGBkaWZmZXJlbmNlIGNvbXBhcmlzb25gLCB2YWx1ZSA9IGAlIGRpZmZlcmVuY2VgKSAlPiUgCiAgZmlsdGVyKGBkaWZmZXJlbmNlIGNvbXBhcmlzb25gID09IGMoIkZlbWFsZS1saW1pdGVkIiwgIk1hbGUtbGltaXRlZCIpKSAlPiUgCiAgZ3JvdXBfYnkoYGRpZmZlcmVuY2UgY29tcGFyaXNvbmApICAlPiUgCiAgc3VtbWFyaXNlKGBNZWFuIHByb3BvcnRpb24gb2Ygb2Zmc3ByaW5nIHByb2R1Y2VkIHJlbGF0aXZlIHRvIGNvbnRyb2xgICA9IG1lYW4oYCUgZGlmZmVyZW5jZWApLAogICAgICAgICAgICBgMi41JWAgPSBxdWFudGlsZShgJSBkaWZmZXJlbmNlYCwgcHJvYnMgPSAwLjAyNSksCiAgICAgICAgICAgIGA5Ny41JWAgPSBxdWFudGlsZShgJSBkaWZmZXJlbmNlYCwgcHJvYnMgPSAwLjk3NSkpICU+JSAKICByZW5hbWUoYEV2b2x1dGlvbiB0cmVhdG1lbnRgID0gYGRpZmZlcmVuY2UgY29tcGFyaXNvbmApICU+JSAKICBwYW5kZXIoc3BsaXQuY2VsbCA9IDQwLCBzcGxpdC50YWJsZSA9IEluZiwgcm91bmQgPSAzKQpgYGAKCiR+JAoKIyBNYWxlIGZpdG5lc3MKCiR+JAoKVG8gZXN0aW1hdGUgdGhlIGZpdG5lc3Mgb2YgbWFsZXMgY2FycnlpbmcgZWFjaCBvZiB0aGUgdGhyZWUgY2hyb21vc29tZSB0eXBlcywgd2UgY29uZHVjdGVkIGFuIGV4cGVyaW1lbnQgdmVyeSBzaW1pbGFyIHRvIHRoZSBmZW1hbGUgZml0bmVzcyBhc3NheS4gSG93ZXZlciwgYmVjYXVzZSBtYWxlIGZpdG5lc3MgaGFzIHN0cm9uZ2VyIGNvdmFyaWFuY2Ugd2l0aCBmZXJ0aWxpc2F0aW9uIGV2ZW50cyB0aGFuIGRvZXMgZmVtYWxlIGZpdG5lc3MsIHdlIGNvbmR1Y3RlZCB0aGUgbWFsZSBmaXRuZXNzIGFzc2F5IHdpdGggYSAxOjIgc2V4IHJhdGlvIChmZW1hbGU6bWFsZSkgcmF0aGVyIHRoYW4gdGhlIDE6MSByYXRpbyB1c2VkIGluIHRoZSBmZW1hbGUgYXNzYXkuIFRoaXMgaW5jcmVhc2VzIHRoZSBzdHJlbmd0aCBvZiBzZXh1YWwgc2VsZWN0aW9uIGFuZCBpcyBhIG1vcmUgYXBwb3ByaWF0ZSB3YXkgdG8gZXhwb3NlIGRpZmZlcmVuY2VzIGluIGZpdG5lc3MgYmV0d2VlbiBncm91cHMgb2YgbWFsZXMuIEFzIHdpdGggdGhlIGZlbWFsZXMsIHdlIGNhbGN1bGF0ZWQgZml0bmVzcyBhcyB0aGUgcHJvcG9ydGlvbiBvZiByZWQgZXllZCBvZmZzcHJpbmcgaW4gdGhlIHZpYWwuIAoKYGBge3J9Cm1hbGVfZml0bmVzcy4wMSA8LQogIGJybShUb3RhbF9yZWRfb2Zmc3ByaW5nIHwgdHJpYWxzKFRvdGFsX29mZnNwcmluZykgfiAxICsgRXZvbHV0aW9uX3RyZWF0bWVudCArIEdGUCArIEJsb2NrICsgKDF8UG9wdWxhdGlvbikgKyAoMXxSZWFyaW5nX3ZpYWwpLAogICAgICBkYXRhID0gbWFsZV9maXRuZXNzLCBmYW1pbHkgPSBiaW5vbWlhbCgpLCAKICAgICAgcHJpb3IgPSBjKHByaW9yKG5vcm1hbCgwLCAxLjUpLCBjbGFzcyA9IEludGVyY2VwdCksCiAgICAgICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMiksIGNsYXNzID0gYiksCiAgICAgICAgICAgICAgICBwcmlvcihleHBvbmVudGlhbCgxKSwgY2xhc3MgPSBzZCkpLAogICAgICBpdGVyID0gMTAwMDAsIHdhcm11cCA9IDgwMDAsIGNoYWlucyA9IDQsIGNvcmVzID0gNCwKICAgICAgY29udHJvbCA9IGxpc3QoYWRhcHRfZGVsdGEgPSAwLjk5OSwgbWF4X3RyZWVkZXB0aCA9IDE1KSwKICAgICAgc2VlZCA9IDIsIGZpbGUgPSAiRml0cy9tYWxlX2ZpdG5lc3MuMDEiKQoKI2FkZF9jcml0ZXJpb24obWFsZV9maXRuZXNzLjAyLCBjcml0ZXJpb24gPSAid2FpYyIpCgpwcmludChtYWxlX2ZpdG5lc3MuMDEpCmBgYAoKQ29uZHVjdCB0aGUgcG9zdGVyaW9yIHByZWRpY3RpdmUgY2hlY2suLi4KCmBgYHtyfQpwcF9jaGVjayhtYWxlX2ZpdG5lc3MuMDEsIHR5cGUgPSAiaGlzdCIsIG5kcmF3cyA9IDExLCBiaW53aWR0aCA9IDEwKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCkdldCBwcmVkaWN0aW9ucyBmcm9tIHRoZSBtb2RlbCBhbmQgcHJlc2VudCB0aGVtIGluIGEgVGFibGUKCmBgYHtyfQoKZHJhd3NfbSA8LSBhc19kcmF3c19kZihtYWxlX2ZpdG5lc3MuMDEpCgpkcmF3c19tYWxlIDwtCiAgZHJhd3NfbSAgJT4lIAogIG11dGF0ZShgRmVtYWxlLWxpbWl0ZWRgID0gaW52X2xvZ2l0X3NjYWxlZChiX0ludGVyY2VwdCArIGJfRXZvbHV0aW9uX3RyZWF0bWVudEZlbWFsZV9saW1pdGVkKSwKICAgICAgICAgYE1hbGUtbGltaXRlZGAgPSBpbnZfbG9naXRfc2NhbGVkKGJfSW50ZXJjZXB0ICsgYl9Fdm9sdXRpb25fdHJlYXRtZW50TWFsZV9saW1pdGVkKSwKICAgICAgICAgQ29udHJvbCA9IGludl9sb2dpdF9zY2FsZWQoYl9JbnRlcmNlcHQpKSAlPiUgCiAgc2VsZWN0KENvbnRyb2wsIGBGZW1hbGUtbGltaXRlZGAsIGBNYWxlLWxpbWl0ZWRgKSAlPiUgCiAgICBwaXZvdF9sb25nZXIoY29scyA9IGMoQ29udHJvbCwgYEZlbWFsZS1saW1pdGVkYCwgYE1hbGUtbGltaXRlZGApLAogICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIkV2b2x1dGlvbl90cmVhdG1lbnQiKSAlPiUgCiAgcmVuYW1lKHByb3BfZm9jYWxfb2Zmc3ByaW5nID0gdmFsdWUpCgpkcmF3c19tYWxlICU+JSAKICBncm91cF9ieShFdm9sdXRpb25fdHJlYXRtZW50KSAlPiUgCiAgc3VtbWFyaXNlKGBFc3RpbWF0ZWQgcHJvcC4gb2Ygb2Zmc3ByaW5nIHNpcmVkYCA9IG1lZGlhbihwcm9wX2ZvY2FsX29mZnNwcmluZyksCiAgICAgICAgICAgIGAyLjUlYCA9IHF1YW50aWxlKHByb3BfZm9jYWxfb2Zmc3ByaW5nLCBwcm9icyA9IDAuMDI1KSwKICAgICAgICAgICAgYDk3LjUlYCA9IHF1YW50aWxlKHByb3BfZm9jYWxfb2Zmc3ByaW5nLCBwcm9icyA9IDAuOTc1KSkgJT4lIAogIHJlbmFtZShgRXZvbHV0aW9uIHRyZWF0bWVudGAgPSBFdm9sdXRpb25fdHJlYXRtZW50KSAlPiUgCiAgcGFuZGVyKHNwbGl0LmNlbGwgPSA0MCwgc3BsaXQudGFibGUgPSBJbmYsIHJvdW5kID0gMykKCiMgbm93IGZpbmQgdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gdGhlIGNvbnRyb2wgYW5kIHRoZSBzZXgtbGltaXRlZCBFdm9sdXRpb25fdHJlYXRtZW50cwoKIyB0aGUgaW52X2xvZ2l0X3NjYWxlZCgpIGZ1bmN0aW9uIGNvbnZlcnRzIHRoZSBwb3N0ZXJpb3IgZHJhd3Mgb250byB0aGUgcmVzcG9uc2Ugc2NhbGUgCgpkcmF3c19tICU+JSAKICBtdXRhdGUocF9jb250cm9sID0gIGludl9sb2dpdF9zY2FsZWQoYl9JbnRlcmNlcHQpLAogICAgICAgICBwX2ZlbWFsZSA9IGludl9sb2dpdF9zY2FsZWQoYl9Fdm9sdXRpb25fdHJlYXRtZW50RmVtYWxlX2xpbWl0ZWQgKyBiX0ludGVyY2VwdCksCiAgICAgICAgIHBfbWFsZSA9IGludl9sb2dpdF9zY2FsZWQoYl9Fdm9sdXRpb25fdHJlYXRtZW50TWFsZV9saW1pdGVkICsgYl9JbnRlcmNlcHQpLAogICAgICAgICBgRmVtYWxlLWxpbWl0ZWRgID0gcF9mZW1hbGUgLyBwX2NvbnRyb2wsCiAgICAgICAgIGBNYWxlLWxpbWl0ZWRgID0gcF9tYWxlIC8gcF9jb250cm9sKSAlPiUgCiAgZ2F0aGVyKGtleSA9IGBkaWZmZXJlbmNlIGNvbXBhcmlzb25gLCB2YWx1ZSA9IGAlIGRpZmZlcmVuY2VgKSAlPiUgCiAgZmlsdGVyKGBkaWZmZXJlbmNlIGNvbXBhcmlzb25gID09IGMoIkZlbWFsZS1saW1pdGVkIiwgIk1hbGUtbGltaXRlZCIpKSAlPiUgCiAgZ3JvdXBfYnkoYGRpZmZlcmVuY2UgY29tcGFyaXNvbmApICAlPiUgCiAgc3VtbWFyaXNlKGBNZWFuIHByb3BvcnRpb24gb2Ygb2Zmc3ByaW5nIHNpcmVkIHJlbGF0aXZlIHRvIGNvbnRyb2xgICA9IG1lYW4oYCUgZGlmZmVyZW5jZWApLAogICAgICAgICAgICBgMi41JWAgPSBxdWFudGlsZShgJSBkaWZmZXJlbmNlYCwgcHJvYnMgPSAwLjAyNSksCiAgICAgICAgICAgIGA5Ny41JWAgPSBxdWFudGlsZShgJSBkaWZmZXJlbmNlYCwgcHJvYnMgPSAwLjk3NSkpICU+JSAKICByZW5hbWUoYEV2b2x1dGlvbiB0cmVhdG1lbnRgID0gYGRpZmZlcmVuY2UgY29tcGFyaXNvbmApICU+JSAKICBwYW5kZXIoc3BsaXQuY2VsbCA9IDQwLCBzcGxpdC50YWJsZSA9IEluZiwgcm91bmQgPSAzKQpgYGAKCiMgQnVpbGRpbmcgRmlndXJlIDEKCmBgYHtyfQoKIyBmZW1hbGUgcGxvdHMKCmZfMSA8LQogIGRyYXdzX2ZlbWFsZSAlPiUgCiAgZ2dwbG90KGFlcyhFdm9sdXRpb25fdHJlYXRtZW50LCBwcm9wX2ZvY2FsX29mZnNwcmluZykpICsgCiAgc3RhdF9leWUoYWVzKGZpbGwgPSBFdm9sdXRpb25fdHJlYXRtZW50KSwgLndpZHRoID0gYygwLjY2LCAwLjk1KSwgYWxwaGEgPSAxKSArICMgd2lkdGggaW5kaWNhdGVzIHRoZSB1bmNlcnRhaW50eSBpbnRlcnZhbHM6IGhlcmUgd2UgaGF2ZSA2NiUgYW5kIDk1JSBpbnRlcnZhbHMKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtZXQuYnJld2VyKCJIaXJvc2hpZ2UiLCAzKSkgKwogIHNjYWxlX3lfY29udGludW91cygiRmVtYWxlIGZpdG5lc3Ncbihwcm9wb3J0aW9uIG9mIG9mZnNwcmluZyBwcm9kdWNlZCkiLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKDAuNCwgMC42LCAwLjgpKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAuNCwgMSkpICsKICB4bGFiKE5VTEwpICsKICB0aGVtZV9idygpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCgpmXzIgPC0KICBkcmF3cyAlPiUgCiAgbXV0YXRlKGBGZW1hbGUtbGltaXRlZGAgPSBiX0V2b2x1dGlvbl90cmVhdG1lbnRGZW1hbGVfbGltaXRlZCwKICAgICAgICAgYE1hbGUtbGltaXRlZGAgPSBiX0V2b2x1dGlvbl90cmVhdG1lbnRNYWxlX2xpbWl0ZWQpICU+JSAKICBnYXRoZXIoa2V5ID0gcGFyYW1ldGVyLCB2YWx1ZSA9IGxvZ29kZHMpICU+JSAKICBmaWx0ZXIocGFyYW1ldGVyID09IGMoIkZlbWFsZS1saW1pdGVkIiwgIk1hbGUtbGltaXRlZCIpKSAlPiUKICBhc190aWJibGUoKSAlPiUgCiAgCiAgZ2dwbG90KGFlcyhwYXJhbWV0ZXIsIGxvZ29kZHMpKSArIAogIHN0YXRfaGFsZmV5ZShhZXMoZmlsbCA9IHBhcmFtZXRlciksIC53aWR0aCA9IGMoMC42NiwgMC45NSkpICsgIyB3aWR0aCBpbmRpY2F0ZXMgdGhlIHVuY2VydGFpbnR5IGludGVydmFsczogaGVyZSB3ZSBoYXZlIDY2JSBhbmQgOTUlIGludGVydmFscwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkZlbWFsZS1saW1pdGVkIiA9ICIjZmZkMDZmIiwgIk1hbGUtbGltaXRlZCIgPSAiIzcyYmNkNSIpKSArIAogIGNvb3JkX2ZsaXAoeWxpbSA9IGMoLTEsIDEpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAyKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IGMoLTEsIDAsIDEpKSArCiAgeGxhYihOVUxMKSArCiAgeWxhYihOVUxMKSArCiAgdGhlbWVfYncoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQoKIyBtYWxlIHBsb3RzCgpmXzMgPC0KICBkcmF3c19tYWxlICU+JSAKICBnZ3Bsb3QoYWVzKEV2b2x1dGlvbl90cmVhdG1lbnQsIHByb3BfZm9jYWxfb2Zmc3ByaW5nKSkgKyAKICBzdGF0X2V5ZShhZXMoZmlsbCA9IEV2b2x1dGlvbl90cmVhdG1lbnQpLCAud2lkdGggPSBjKDAuNjYsIDAuOTUpLCBhbHBoYSA9IDEpICsgIyB3aWR0aCBpbmRpY2F0ZXMgdGhlIHVuY2VydGFpbnR5IGludGVydmFsczogaGVyZSB3ZSBoYXZlIDY2JSBhbmQgOTUlIGludGVydmFscwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG1ldC5icmV3ZXIoIkhpcm9zaGlnZSIsIDMpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKCJNYWxlIGZpdG5lc3Ncbihwcm9wb3J0aW9uIG9mIG9mZnNwcmluZyBzaXJlZCkiLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKDAuNCwgMC42LCAwLjgpKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAuNCwgMSkpICsKICB4bGFiKCJFdm9sdXRpb25hcnkgaGlzdG9yeSIpICsKICB0aGVtZV9idygpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCgpmXzQgPC0KICBkcmF3c19tICU+JSAKICBtdXRhdGUoYEZlbWFsZS1saW1pdGVkYCA9IGJfRXZvbHV0aW9uX3RyZWF0bWVudEZlbWFsZV9saW1pdGVkLAogICAgICAgICBgTWFsZS1saW1pdGVkYCA9IGJfRXZvbHV0aW9uX3RyZWF0bWVudE1hbGVfbGltaXRlZCkgJT4lIAogIGdhdGhlcihrZXkgPSBwYXJhbWV0ZXIsIHZhbHVlID0gbG9nb2RkcykgJT4lIAogIGZpbHRlcihwYXJhbWV0ZXIgPT0gYygiRmVtYWxlLWxpbWl0ZWQiLCAiTWFsZS1saW1pdGVkIikpICU+JQogIGFzX3RpYmJsZSgpICU+JSAKICAjbXV0YXRlKHBhcmFtZXRlciA9ZmFjdG9yKHBhcmFtZXRlciwgbGV2ZWxzPWMoIlNELU1hZCIsICJTRC03MiIsICJTRC01IikpKSAlPiUKICAKICBnZ3Bsb3QoYWVzKHBhcmFtZXRlciwgbG9nb2RkcykpICsgCiAgc3RhdF9oYWxmZXllKGFlcyhmaWxsID0gcGFyYW1ldGVyKSwgLndpZHRoID0gYygwLjY2LCAwLjk1KSkgKyAjIHdpZHRoIGluZGljYXRlcyB0aGUgdW5jZXJ0YWludHkgaW50ZXJ2YWxzOiBoZXJlIHdlIGhhdmUgNjYlIGFuZCA5NSUgaW50ZXJ2YWxzCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiRmVtYWxlLWxpbWl0ZWQiID0gIiNmZmQwNmYiLCAiTWFsZS1saW1pdGVkIiA9ICIjNzJiY2Q1IikpICsgCiAgY29vcmRfZmxpcCh5bGltID0gYygtMSwgMSkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9IDIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gYygtMSwgMCwgMSkpICsKICB4bGFiKE5VTEwpICsKICB5bGFiKCJMb2ctb2RkcyBtZWFuIGRpZmZlcmVuY2UgZnJvbSBjb250cm9sIikgKwogIHRoZW1lX2J3KCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKCgooZl8xICsgZl8yKSAvKGZfMyArIGZfNCkKCmBgYAoKKipGaWd1cmUgMSoqOiAqKmEqKiBzaG93cyB0aGUgZXN0aW1hdGVkIG1lYW4gZmVtYWxlIGZpdG5lc3MgZm9yIGZsaWVzIGNhcnJ5aW5nIGF1dG9zb21lcyB0aGF0IGhhZCBwcmV2aW91c2x5IGV4cGVyaWVuY2VkIHVuY29uc3RyYWluZWQgaW5oZXJpdGFuY2UgKGNvbnRyb2wpLCBmZW1hbGUtbGltaXRlZCBpbmhlcml0YW5jZSBvciBtYWxlLWxpbWl0ZWQgaW5oZXJpdGFuY2UuICoqYioqIHNob3dzIHRoZSBsb2ctb2RkcyBtZWFuIGRpZmZlcmVuY2UgaW4gbWVhbnMgYmV0d2VlbiB0aGUgc2V4LWxpbWl0ZWQgdHJlYXRtZW50cyBhbmQgdGhlIGNvbnRyb2wgZXZvbHV0aW9uYXJ5IHRyZWF0bWVudC4gKipjKiogYW5kICoqZCoqIGRlcGljdCB0aGUgc2FtZSB0aGluZ3MgYXMgKiphKiogYW5kICoqYioqLCBleGNlcHQgZm9yIGVzdGltYXRlZCBtZWFuIG1hbGUgZml0bmVzcy4KCg==